package org.melanesia.ref;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * This class is an extension for {@link PhantomReference} which allows for
 * keeping: <li>
 * <ol>
 * A trace (like in an exception) of the place that the observed object was
 * created (actually, added to monitoring, but this is usually close enough).
 * </ol>
 * <ol>
 * A collection of releasable resources, to be released if object becomes
 * "phantom reachable" and the user of the object would not release them
 * manually.
 * </ol>
 * </li>
 *
 * @author marcin.kielar
 * @see ReferenceMonitor
 */
public final class ObjectReference extends PhantomReference<Object> {

    /** Collection of releasable resources. */
    private final Set<ReleasableResource<?>> resources = new LinkedHashSet<ReleasableResource<?>>();

    /** Trace. */
    private final Throwable trace;

    /**
     * Constructs new {@code ObjectReference}.
     *
     * @param q
     *            reference queue
     * @param referent
     *            object to refer
     * @param trace
     *            stack trace of the creation of the object
     */
    public ObjectReference(final ReferenceQueue<? super Object> q, final Object referent, final Throwable trace) {
        super(referent, q);
        this.trace = trace;
    }

    /**
     * Attaches releasable resource to this reference.
     *
     * @param resource
     *            resource to attach
     * @return this reference
     */
    public ObjectReference withResource(final ReleasableResource<?> resource) {
        resources.add(resource);
        return this;
    }

    /**
     * Returns the list of attached resources.
     *
     * @return list of resources attached to this reference
     */
    public Set<ReleasableResource<?>> getResources() {
        return resources;
    }

    /**
     * Returns the stack trace of creation of the referenced object.
     *
     * @return stack trace of creation of the referenced object
     */
    public Throwable getTrace() {
        return trace;
    }
}
